import {
  observable,
  toJS,
  computed,
  action,
  extendObservable,
} from 'mobx'
import { topicSchema, replySchema } from '../utils/variable-define'
import { get, post } from '../utils/http'

const createTopic = (topic) => {
  return Object.assign({}, topicSchema, topic) // 返回所有字段都有定义的topic对象
}

const createReply = (reply) => {
  return Object.assign({}, replySchema, reply)
}

/**
 * 为了以后扩展更加容易，创建一个类，让每个话题都放到这个类中
 * 即变成类的实例，更好的控制话题
 * 让数据使用 mobx 具有的特性
 */
export class Topic { // 创建 topic 的时候就是所有有定义的字段都添加 observable 属性并附加this
  constructor(data) {
    extendObservable(this, data) // 把数据直接扩展到 this 上并使用 observeable
  }

  @observable syncing = false // 是否异步操作请求数据，在组件中反应正在加载的操作

  @observable createdReplies = [] // 每个话题都可以新建一个回复，默认空数组

  @action doReply(content) {
    return new Promise((resolve, reject) => {
      post(`/topic/${this.id}/replies`, {
        needAccessToken: true,
      }, { content })
        .then((resp) => {
          if (resp.success) {
            this.createdReplies.push(createReply({
              id: resp.reply_id,
              content,
              create_at: Date.now(),
            }))
            resolve()
          } else {
            reject(resp)
          }
        }).catch(reject)
    })
  }
}

class TopicStore {
  @observable topics

  @observable details // 数组

  @observable syncing // 是否正在处理数据请求

  @observable createdTopics = [] // 新建话题保存在这里

  // constructor({ syncing, topics, details } = { syncing: false, topics: [], details: [] }) {
  constructor({ syncing = false, topics = [], details = [] } = {}) { // 整个对象默认等于 空对象
    // 初始化数据，设置默认值
    this.syncing = syncing
    this.topics = topics.map(topic => new Topic(createTopic(topic))) // 数组使用map
    this.details = details.map(topic => new Topic(createTopic(topic))) // 数组使用map
  }
  /**
   * 上面是 topic 的定义
   * 下面获取 topic 数据
   */

  addTopic(topic) { // 往 topics 里加入新的 topic 对象
    this.topics.push(new Topic(createTopic(topic)))
  }

  @computed get detailMap() { // 方便获取某个 id 下的 detail
    return this.details.reduce((result, detail) => {
      result[detail.id] = detail // eslint-disable-line
      return result
    }, {})
  }

  @action fetchTopics(tab) {
    this.syncing = true // 开始请求数据之前设置为 true 表示正在异步获取数据
    this.topics = [] // 获取之前先清空
    return new Promise((resolve, reject) => {
      get('/topics', {
        mdrender: false, // markdown 字符串是否转义成 html 字符串,不转义还可以继续编辑 markdown
        tab,
      }).then((resp) => {
        if (resp.success) { // 把拿到的所有 topic 都放到 this.topics 里
          resp.data.forEach((topic) => {
            this.addTopic(topic)
          })
          resolve() // 数据获取成功
        } else {
          reject() // 数据获取失败
        }
        this.syncing = false // 数据获取结束
      }).catch((err) => { // 出现任何异常
        reject(err)
        this.syncing = false // 出现异常数据获取结束
      })
    })
  }

  @action getTopicDetail(id) {
    return new Promise((resolve, reject) => {
      console.log("this.details: ", this.details) // eslint-disable-line
      if (this.detailMap[id]) { // 有数据，即已经获取过该id的详情数据
        resolve(this.detailMap[id])
      } else { // 没有就获取
        get(`/topic/${id}`, {
          mdrender: false, // 不要转化 markdown 格式
        }).then((resp) => {
          if (resp.success) {
            const topic = new Topic(createTopic(resp.data)) // 新建一个 topic 对象
            this.details.push(topic) // 获取的数据放入 details 数组中
            resolve(topic) // 就可以很方便的根据id去 detailMap 获取有详情的话题对象
          } else {
            reject()
          }
        }).catch(reject)
      }
    })
  }

  @action createTopic(title, tab, content) {
    return new Promise((resolve, reject) => {
      post('/topics', {
        needAccessToken: true,
      }, {
        title, tab, content,
      }).then((resp) => {
        if (resp.success) {
          const topic = {
            title,
            tab,
            content,
            id: resp.topic_id,
            create_at: Date.now(),
          }
          this.createdTopics.push(new Topic(createTopic(topic)))
          resolve()
        } else {
          reject()
        }
      }).catch(reject)
    })
  }

  toJson() {
    return {
      topics: toJS(this.topics),
      syncing: this.syncing,
      details: toJS(this.details),
    }
  }
}

export default TopicStore
